package com.cn.server.sever;

import com.cn.common.core.model.websocket.HttpRequest;
import com.cn.common.core.model.websocket.HttpResponse;
import com.cn.common.core.model.websocket.HttpResult;
import com.cn.common.module.chat.websocket.ChatHttpRequest;
import com.cn.common.module.platform.PlatformType;
import com.cn.common.module.player.websocket.PlayerHttpResponse;
import com.cn.common.utils.GsonHelperUtils;
import com.cn.server.module.player.service.PlayerService;
import com.google.gson.reflect.TypeToken;
import io.netty.channel.*;

import com.cn.common.core.model.Request;
import com.cn.common.core.model.Response;
import com.cn.common.core.model.Result;
import com.cn.common.core.model.ResultCode;
import com.cn.common.core.serial.Serializer;
import com.cn.common.core.session.Session;
import com.cn.common.core.session.SessionImpl;
import com.cn.common.core.session.SessionManager;
import com.cn.common.module.ModuleId;
import com.cn.server.module.player.dao.entity.Player;
import com.cn.server.scanner.Invoker;
import com.cn.server.scanner.InvokerHoler;
import com.google.protobuf.GeneratedMessage;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 消息接受处理类
 */
public class ServerHandler extends SimpleChannelInboundHandler {
    private PlayerService playerService;

    public ServerHandler(PlayerService playerService) {
        this.playerService = playerService;
    }

    public ServerHandler() {
    }

    /**
     * 接收消息
     */
    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object request) throws Exception {
        //
        System.out.println("channelread:" + Thread.currentThread().getName());
        Channel channel = ctx.channel();
        ChannelPipeline pipeline = channel.pipeline();
        Session session = new SessionImpl(channel);
        Player attachment = (Player) session.getAttachment();
        if (attachment != null) {
            long playerId = attachment.getPlayerId();
            ConcurrentHashMap<Long, Session> onlineSessions = SessionManager.getOnlineSessions();
            //如果已经存在此session，则用新的session对象替换掉，但是channel不变
            if (onlineSessions.get(playerId) != null) {
                SessionManager.putSession(playerId, session);
            }
            new Thread();
        }
        //如果是pc的请求
        if (request instanceof Request) {
            //和decoder类作比较
            System.out.println("当前线程========" + Thread.currentThread().getName());
            Request request1 = (Request) request;
            handlerPCMessage(session, request1);
            //如果是浏览器的请求
        } else if (request instanceof TextWebSocketFrame) {
            TextWebSocketFrame socketFrame = (TextWebSocketFrame) request;
            String text = socketFrame.text();
            HttpRequest httpRequest = GsonHelperUtils.fromJson(text, HttpRequest.class);
            handlerBrowserMessage(session, httpRequest);
        }

    }

    private void handlerBrowserMessage(Session session, HttpRequest httpRequest) {
        //请求中的请求体
        String requestData = httpRequest.getRequestData();
        //获取请求中的module和cmd号，用来判断调用哪些方法
        //moduleId
        short module = httpRequest.getModule();
        //cmd号，
        short cmd = httpRequest.getCmd();
        //如果是ping消息
        if (module == ModuleId.PING) {
            return;
        }
        HttpResponse response = new HttpResponse(module, cmd);
        try {
            //获取执行器
            Invoker invoker = InvokerHoler.getInvoker(PlatformType.FROM_BROSWER, module, cmd);
            if (invoker != null) {
                Object invoke = null;
                //如果是玩家模块
                if (module == ModuleId.PLAYER) {
                    //注册登录
                    invoke = invoker.invoke(session, requestData);
                    //否则是聊天模块
                } else if (module == ModuleId.CHAT) {
                    Player attachment = (Player) session.getAttachment();
                    //如果session过期，提示重新登录，
                    if (attachment == null) {
                        //如果没有登录
                        //会话未登录拒绝请求
                        response.setStateCode(ResultCode.LOGIN_PLEASE);
                        writeResponse(session, response);
                        return;
                        // 否则直接发送消息
                    } else {
                        invoke = invoker.invoke(attachment.getPlayerId(), requestData);
                    }
                }
                HttpResult<PlayerHttpResponse> result = (HttpResult<PlayerHttpResponse>) invoke;

                //判断执行器是否执行成功
                //如果成功，返回相应结果
                if (result.getResultCode() == ResultCode.SUCCESS) {
                    PlayerHttpResponse content = result.getContent();
                    response.setResponseData(content);
                    writeResponse(session, response);
                } else {
                    response.setStateCode(result.getResultCode());
                    writeResponse(session, response);
                }

            } else {
                response.setStateCode(ResultCode.NO_INVOKER);
                writeResponse(session, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //登录不成果，返回unknown错误
            response.setStateCode(ResultCode.UNKOWN_EXCEPTION);
            writeResponse(session, response);
        }


    }

    private void writeResponse(Session session, HttpResponse response) {
        String json = GsonHelperUtils.toJson(response);
        TextWebSocketFrame frame = new TextWebSocketFrame(json);
        session.write(frame);
    }

    /**
     * 消息处理
     *
     * @param request
     */
    private void handlerPCMessage(Session session, Request request) {
        short module = request.getModule();
        short cmd = request.getCmd();
        Response response = new Response(module, cmd);

        System.out.println("module:" + module + "   " + "cmd：" + cmd);
        //如果是ping消息
        if (module == ModuleId.PING) {
            return;
        }
        //根据module和cmd号获取命令执行器，执行相应的方法
        Invoker invoker = InvokerHoler.getInvoker(PlatformType.FROM_PC, module, cmd);
        if (invoker != null) {
            try {
                Result<?> result = null;
                //假如是玩家模块传入channel参数，否则传入playerId参数
                if (module == ModuleId.PLAYER) {
                    //执行
                    result = (Result<?>) invoker.invoke(session, request.getData());
                } else if (module == ModuleId.CHAT) {
                    //绑定对象就是player
                    Object attachment = session.getAttachment();
                    //如果已经登录了,执行聊天
                    if (attachment != null) {
                        Player player = (Player) attachment;
                        player.setPlatType(PlatformType.FROM_PC);
                        result = (Result<?>) invoker.invoke(player.getPlayerId(), request.getData());

                    } else {
                        //如果没有登录
                        //会话未登录拒绝请求
                        response.setStateCode(ResultCode.LOGIN_PLEASE);
                        session.write(response);
                        return;
                    }
                }
                //判断执行器执行是否成功，将执行的结果设置到response中
                //判断请求是否成功
                if (result.getResultCode() == ResultCode.SUCCESS) {
                    //回写数据
                    Object object = result.getContent();
                    if (object != null) {
                        if (object instanceof Serializer) {
                            Serializer content = (Serializer) object;
                            response.setData(content.getBytes());
                        } else if (object instanceof GeneratedMessage) {
                            GeneratedMessage content = (GeneratedMessage) object;
                            response.setData(content.toByteArray());
                        } else {
                            System.out.println(String.format("不可识别传输对象:%s", object));
                        }
                    }
                    session.write(response);
                } else {
                    //返回错误码
                    response.setStateCode(result.getResultCode());
                    session.write(response);
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
                //系统未知异常
                response.setStateCode(ResultCode.UNKOWN_EXCEPTION);
                session.write(response);
            }
        } else {
            //未找到执行者
            response.setStateCode(ResultCode.NO_INVOKER);
            session.write(response);
            return;
        }
    }

    /**
     * 断线移除会话
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Session session = new SessionImpl(ctx.channel());
        //获取绑定的对象
        Object object = session.getAttachment();
        if (object != null) {
            Player player = (Player) object;
            //从sessionManager中移出
            SessionManager.removeSession(player.getPlayerId());
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }

    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            //如果超时了，关闭channel
            if (idleStateEvent.state() == IdleState.ALL_IDLE) {
                final Channel channel = ctx.channel();
                ChannelFuture future = channel.write("你超时了！");
                //收到提示消息后关闭会话
                future.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture channelFuture) throws Exception {
                        ctx.channel().close();
                    }
                });
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
